/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
/*
 * Copyright 2009, Center for Advanced Information Systems,Nanyang Technological University
 *
 * File name: BuildSpig.java
 *
 * Abstract: The main SPIG Graph builiding algorithm
 *
 * Current Version:      0.1
 * Auther:               Jin Changjiu
 * Modified Date:        Jun 20,2010
 *
 */
package gblend.exactquery;

//import gblend.adjlistgraph.ALGraph;
import gblend.adjlistgraph.FsgIdEntry;
import gblend.frequentindex.BuildFreqIndex;
import gblend.frequentindex.FGraph;
//import gblend.infrequentindex.BuildCam;
import gblend.infrequentindex.BuildInfreqIndex;
//import gblend.largegraph.structure.IntersectSet;
import java.util.HashSet;
import java.util.Iterator;
import java.util.ArrayList;

/**
 *
 * @author c4jin
 */
public class BuildSpig {

    //  private BuildCam bc = new BuildCam();
//Attach the feature information of SPIG
    public SpindleGraph buildSpiGraph(SNode query, SNode seed, QueryEngine qe, ArrayList<SpindleGraph> spindleGraphSet) {
        System.out.println(">>> BuildSpig.buildSpiGraph");
        CreateSpindleGraph csg = new CreateSpindleGraph();
        SpindleGraph spigraph = csg.constructSPIG(query, seed);

        //firstly, check the type of the newest edge and attach its feature ids
        mineSeed(spigraph.getNode(0), qe);

        for (int i = 1; i < spigraph.getSize(); i++)//start from i=1,because node(0) has no parents
        {
            SNode nodei = spigraph.getNode(i);
            for (int j = 0; j < i; j++)// j only could be the nodes in front of i
            {
                if (spigraph.getEdge(j, i) == 1)//j is a parent of i, get features from j to i
                {
                    //add the features of nodej to nodei
                    addParentFeatures(spigraph.getNode(j), nodei);
                }
            }
            if (!nodei.isCandParentListEmpty()) {
                System.out.println(" *** Node #" + i + "is Normal INF #1");
                checkLargestSubgraph(nodei, spindleGraphSet);
                combineIdsLists(nodei, qe);
                try {
                    nodei.finaliseCandParentList();
                } catch (Exception e) {
                    e.printStackTrace();
                }
            } //all its parents in spindle graph are frequent
            else {
                System.out.print(" *** Node #" + i + "is NOT a Normal INF #1");
                if (nodei.getDifIds().isEmpty()) {
                    System.out.print(" *** Node #" + i + " has NO DIF parent");
                    //check if nodei is a frequent fragment in MF or DF index
                    qe.SearchA2Findex(nodei);
                    //if nodei is not a frequent one
                    if (nodei.getItsFreqId() == -1) {
                        System.out.print(" *** Node #" + i + " is NOT FREQ");
                        checkDifPosition(nodei, qe);// check nodei in Difindex
                        //check nodei's largest subgraph without the newest edge
                        //if no difs in nodei, is nodei a dif?
                        if (nodei.getItsDifId() == -1) {
                            System.out.println(" *** Node #" + i + "is Normal INF #2");
                            checkLargestSubgraph(nodei, spindleGraphSet);
                            combineIdsLists(nodei, qe);
                            try {
                                nodei.finaliseCandParentList();
                            } catch (Exception e) {
                                e.printStackTrace();
                            }
                        } else {
                            System.out.println(" *** Node #" + i + "is DIF #1");
                            nodei.resetCandParentList();
                        }
                    } else {
                        System.out.println(" *** Node #" + i + "is FREQ #1");
                        nodei.resetCandParentList();
                    }
                } else //if one of nodei's parents is infrequent, nodei is a common infrequent one
                {

                    System.out.print("*** Node #" + i + " has DIF parent, maybe it's also a DIF");
                    checkDifPosition(nodei, qe);// check nodei in Difindex
                    if (nodei.getItsDifId() == -1) {
                        System.out.println("*** Node #" + i + " is a Normal INF #3");
                        //get features from its largest subgraph without new edge
                        checkLargestSubgraph(nodei, spindleGraphSet);
                        combineIdsLists(nodei, qe);
                        try {
                            nodei.finaliseCandParentList();
                        } catch (Exception e) {
                            e.printStackTrace();
                        }
                    } else {
                        System.out.println("*** Node #" + i + " is a DIF #2");
                        nodei.resetCandParentList();
                    }
                }
            }
        }
        spigraph.print();
        return spigraph;

    }

    //check the type of the newest edge
    private void mineSeed(SNode snode, QueryEngine qe) {
        String snodecam = snode.getCam();
        System.out.println(">>> BuildSpig:mineSeed: snode cam is = " + snodecam);
        BuildFreqIndex findex = qe.getfindex();
        //is it a frequent one
        FGraph fgph = findex.getFreqGraph();
        /*int fgphsize = fgph.getSize();
        for(int i=0; i< fgphsize;i++)
        {
        ALGraph fnode = fgph.getNode(i);
        //  System.out.println("fnode i="+i+" cam="+fnode.getCam());
        if(snodecam.equals(fnode.getCam()))
        {*/
        int idx = fgph.getIndex(snodecam);
        if (idx != -1) {
            snode.setItsFreqId(idx);
            System.out.println("mineSeed - snode set its freq id = " + idx);
        }
        /*     break;
        }

        }*/
        //is it a dif?
        if (snode.getItsFreqId() == -1) {
            checkDifPosition(snode, qe);
        }

    }

//check the DIF id of node
    private void checkDifPosition(SNode node, QueryEngine qe) {
        System.out.println(">>> BuildSpig.checkDifPosition");
        BuildInfreqIndex infindex = qe.getinfindex();
        int idx = infindex.getIindexFromCam(node.getCam());
        if (idx != -1) {
            node.setItsDifId(idx);//nodei is the Nth element in A2I index
        }
        /*Vector<ALGraph> infgphs = infindex.getInfGraph();
        int infgsize = infgphs.size();
        for (int i = 0; i < infgsize; i++) {
        ALGraph ig = infgphs.elementAt(i);
        if (node.getCam().equals(ig.getCam())) {
        node.setItsDifId(i);//nodei is the Nth element in A2I index
        break;
        }
        }*/
    }

    //find out snode's largest subgraph without the new edge in the previous SPIG graph
    private void checkLargestSubgraph(SNode snode, ArrayList<SpindleGraph> spindleGraphSet) {
        int preLargestEdge = snode.getEdge(0, 1);//the largest edge in snode

        ArrayList<Integer> edgelabelset = new ArrayList<Integer>();
        edgelabelset.addAll(snode.getEdgelabelSet());
        edgelabelset.remove((Integer) preLargestEdge);//construct the edge label set for the largest subgraph
        // int largestEdge = edgelabelset.lastElement();//the new largest edge
        int elssize = edgelabelset.size();
        //the spindle graph with the largest edge in subExnode
        Iterator<Integer> elsi = edgelabelset.iterator();
        while (elsi.hasNext()) {
            int elsie = elsi.next();
            if (elsie >= elssize) {
                SpindleGraph pregraph = spindleGraphSet.get(elsie - 1);//problem is here, spindleGraphSet starts from 0
                int pgphsize = pregraph.getSize();
                for (int i = (elssize - 1); i < pgphsize; i++) {
                    if (pregraph.getNode(i).getEdgelabelSet().equals(edgelabelset)) {
                        //add the features of subExnode to exnode
                        System.out.print("Another largest subgraph:");
                        pregraph.getNode(i).print();
                        addParentFeatures(pregraph.getNode(i), snode);
                        return;
                    }
                }
            }
        }
    }

//add nodep's features to nodec
    private void addParentFeatures(SNode nodep, SNode nodec) {
        // System.out.println(">>> BuildSpig.addParentFeature");
        if (nodep.getItsDifId() != -1) {
            nodec.setDifIds(nodep.getItsDifId());
        } else if (nodep.getItsFreqId() != -1) {
            nodec.setFreIds(nodep.getItsFreqId());
            //set the nodep' cluster id to nodec, if nodep's cluster exists
            if (nodep.getClusterId() != -1) {
                nodec.setClusterList(nodep.getItsFreqId(), nodep.getClusterId());
            }

            /*for (Iterator itr = nodep.getClusters().iterator(); itr.hasNext();) {
            int cid = (Integer) itr.next();
            nodec.setClusters(cid);
            }*/
        } else {
            nodec.addCandParentEntrySet(nodep.getCandParentList().getSet());
            /*if (!nodep.getDifIds().isEmpty()) {
            for (Iterator itr = nodep.getDifIds().iterator(); itr.hasNext();) {
            int infid = (Integer) itr.next();
            nodec.setDifIds(infid);
            }
            }
            if (!nodep.getFreIds().isEmpty()) {
            for (Iterator<Integer> itr = nodep.getFreIds().iterator(); itr.hasNext();) {
            int fid = itr.next();
            nodec.setFreIds(fid);
            }
            }*/
        }
    }

    private void combineIdsLists(SNode nodei, QueryEngine qe) {
        HashSet<Integer> freqids = nodei.getFreIds();
        // if (!freqids.isEmpty()) {
        Iterator<Integer> fidi = freqids.iterator();
        if ((nodei.getEnum() - 1) <= qe.getPara().getb()) {
            System.out.print("MF: ");
            while (fidi.hasNext()) {
                HashSet<FsgIdEntry> tmpset = new HashSet<FsgIdEntry>();

                qe.fetchIdsetMFindex(tmpset, fidi.next());
                System.out.print(tmpset + ",");
                nodei.addCandParentEntrySet(tmpset);
            }
        } else {
            System.out.print("DF: ");
            while (fidi.hasNext()) {
                HashSet<FsgIdEntry> tmpset = new HashSet<FsgIdEntry>();
                int gid = fidi.next();
                qe.fetchIdsetDFindex(tmpset, gid, nodei.getClusterIdFromList(gid));
                System.out.print(tmpset + ",");
                nodei.addCandParentEntrySet(tmpset);
            }
        }
        System.out.println();

        freqids = nodei.getDifIds();
        //   if (!freqids.isEmpty()) {
        Iterator<Integer> fidi1 = freqids.iterator();
        while (fidi1.hasNext()) {
            HashSet<FsgIdEntry> tmp = new HashSet<FsgIdEntry>(qe.fetchIdsetA2I(fidi1.next()));
            System.out.print(tmp + ",");
            nodei.addCandParentEntrySet(tmp);
        }
        System.out.println();

        //    System.out.println("nodei #.. has idlist size=" + nodei.getCandParentList().getSet().size());
    }
}
